package com.fg.cloud.framework.shiro.realm;

import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.fg.cloud.common.ServiceException;
import com.fg.cloud.common.shiro.ShiroUser;
import com.fg.cloud.common.shiro.UserUtils;
import com.fg.cloud.manager.entry.factory.vo.FactoryUserVo;
import com.fg.cloud.manager.service.factory.FactoryUserService;
import com.fg.cloud.manager.service.system.MenuService;
import com.fg.cloud.manager.service.system.RoleService;
import com.google.common.collect.Sets;

/**
 * shiro权限认证模块
 * @author around
 * @date 2017-7-21
 */
public class ShiroDbRealm extends AuthorizingRealm {

    private static Logger LOGGER = LoggerFactory.getLogger(ShiroDbRealm.class);

    @Autowired
    private FactoryUserService shiro_factoryUser;
    @Autowired
    private RoleService shiro_factoryRole;
    @Autowired
    private MenuService shiro_factoryMenu;

    /**
     * Shiro登录认证(原理：用户提交 用户名和密码  --- shiro 封装令牌 ---- realm 通过用户名将密码查询返回 ---- shiro 自动去比较查询出密码和用户输入密码是否一致---- 进行登陆控制 )
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authcToken) throws AuthenticationException {
        LOGGER.info("Shiro开始登录认证");
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        String type = token.getUsername().substring(0, 1);
        token.setUsername(token.getUsername().substring(1));
        
        if(StringUtils.isEmpty(type)) throw new ServiceException("登录状态校验失败，请重试");
        
        FactoryUserVo user = shiro_factoryUser.selectUserByUserName(token.getUsername());
        
        
        
        
        //账号不存在
        if (user == null) {
            throw new UnknownAccountException();
        }
        //密码错误
        if (!user.getPassword().equals(String.valueOf(token.getPassword()))) {
        	throw new IncorrectCredentialsException();
        }
        //账号未启用
        if (user.getStatus() != 1) {
        	throw new DisabledAccountException();
        }
        
        Set<String> roles = shiro_factoryRole.findByUserId(user.getId());
        //List<Resource> resource = shiro_factoryMenu.findByUserId(user.getId(), user.getUserType());
        ShiroUser shiroUser = new ShiroUser(user.getId(), user.getUserName(), user.getTrueName(), roles);
        
        //shiroUser.setResourceList(resource);
        //user.setMenuList(resource);
        user.setPassword(null);
        //修改用户session
        setCurrentUser(user);
        // 认证缓存信息，不做自定义加盐密码认证
        return new SimpleAuthenticationInfo(shiroUser, token.getPassword(), getName());
    }

    /**
     * Shiro权限认证
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
        Set<String> urlSet = shiro_factoryMenu.findMenuUrlByUserId(shiroUser.getId());
        shiroUser.urlSet = urlSet;
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermissions(urlSet);
        info.addRoles(shiroUser.getRoleList());
        return info;
    }
    
    
    private void setCurrentUser(Object user){
        UserUtils.setCurrentUser(user);
    }
}
